package org.spring.boot.func.proxy.handel;

import org.spring.boot.func.annotation.FuncLambda;
import org.spring.boot.func.container.FuncMethod;
import org.spring.boot.func.proxy.FuncProxyFactory;
import org.spring.boot.func.type.FuncLambdaType;
import org.spring.boot.func.utils.FuncString;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.support.*;
import org.springframework.core.type.MethodMetadata;
import org.springframework.util.Assert;

import java.util.List;
import java.util.Map;

/**
 * @author Yiur
 */
public class FuncBeanHandel {

    private final BeanDefinitionRegistry registry;

    public FuncBeanHandel(BeanDefinitionRegistry registry) {
        this.registry = registry;
    }

    public String resolve(MethodMetadata methodMetadata, Map<String, List<FuncMethod>> beans) {
        Map<String, Object> attributes = methodMetadata.getAnnotationAttributes(FuncLambda.class.getName());

        String beanName = (String) attributes.get(FuncLambdaType.BEAN.value);
        String[] refs = (String[]) attributes.get(FuncLambdaType.REFS.value);
        if (beanName.equals(FuncString.STRING_EMPTY)) {
            beanName = FuncString.lowercaseFirstLetter(((Class<?>) attributes.get(FuncLambdaType.CLASS_FILE.value)).getSimpleName());
        }

        if (beans.get(beanName) != null) {
            return beanName;
        }

        try {
            String beanClassName = registry.getBeanDefinition((String) attributes.get(FuncLambdaType.BEAN.value)).getBeanClassName();
            if (beanClassName != null) {
                Assert.isTrue(false, FuncString.format("An object named (?) has been configured. If it belongs to a function that configures this object anonymously, please use ref = true", beanName));
                return beanName;
            }
        } catch (NoSuchBeanDefinitionException ignored) {
        }

        BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition((Class<?>) attributes.get(FuncLambdaType.CLASS_FILE.value));
        GenericBeanDefinition definition = (GenericBeanDefinition) builder.getRawBeanDefinition();

        definition.getPropertyValues().add("beanName", beanName);
        definition.getPropertyValues().add("refs", refs);
        definition.getPropertyValues().add("interfaceClass", definition.getBeanClassName());
        definition.getPropertyValues().add("classObject", methodMetadata.getDeclaringClassName());
        definition.setBeanClass(FuncProxyFactory.class);
        definition.setAutowireMode(GenericBeanDefinition.AUTOWIRE_BY_TYPE);
        registry.registerBeanDefinition(beanName, definition);
        return beanName;
    }

}
